﻿#include "GenerateH26XWindow.h"
#include <QDebug>
#include <QFileDialog>
#include <QMessageBox>
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavutil/avutil.h"
}


GenerateH26XWindow::GenerateH26XWindow(QWidget* parent)
	: QWidget(parent)
{
	ui.setupUi(this);
	this->setWindowTitle("录屏后将数据存储成H264或H265");
	setAttribute(Qt::WA_DeleteOnClose, true);  // 关闭时自动销毁窗口
	codecId = AV_CODEC_ID_H264;
}

void GenerateH26XWindow::onVideoFormatChanged(int pos)
{
	switch (pos)
	{
	case 0:
		codecId = AV_CODEC_ID_H264;
		break;
	case 1:
		codecId = AV_CODEC_ID_HEVC;
		break;
	}
}


void GenerateH26XWindow::choiceOutputFilePathFunc()
{
	QString filter = "所有文件(*.*)"; //文件过滤器
	QString filePath = QFileDialog::getSaveFileName(this, "选择文件输出目录", "", filter);
	this->outFilePath = filePath;
	this->ui.outputPathEdit->setText(this->outFilePath);
}

void GenerateH26XWindow::startScreenFunc()
{
	isClickedRecord = true;
	QString filePath = ui.outputPathEdit->text();
	if (filePath.isEmpty()) {
		QMessageBox::warning(this, "温馨提示", "输入、输出文件的路径不能为空");
		return;
	}
	//开始录屏，开启后可得到屏幕宽高
	TonyCaptureScreen::Get()->outFilePath = filePath;
	TonyCaptureScreen::Get()->Start();
	int screenWidth = TonyCaptureScreen::Get()->getWidth();
	int screenHeight = TonyCaptureScreen::Get()->getHeight();
	//编码器
	encoder = new YEncoder();
	auto mContext = encoder->Create(codecId,true);
	mContext->width = screenWidth;
	mContext->height = screenHeight;
	encoder->setContext(mContext);
	encoder->SetOpt("crf", 18); //恒定速率因子（CRF）
	encoder->Open();
	encoder->InitSwsCtx();

	//文件写入工具
	writer = BinaryFileWriter::Create();
	writer->Init(filePath.toStdString());
	// 创建并启动后台线程
	renderThread = std::make_unique<std::thread>(&GenerateH26XWindow::Save, this);
}

void GenerateH26XWindow::stopScreenFunc()
{
	if (isClickedRecord) {
		TonyCaptureScreen::Get()->Stop();
		isSaveing = false;
		if (renderThread) {
			renderThread->join();
		}
		if (writer) {
			writer->Close();
			writer = nullptr;
		}
		if (encoder) {
			encoder->Release();
			delete encoder;
			encoder = nullptr;
		}
	}
}

void GenerateH26XWindow::Save()
{
	int count = 0;
	auto frame = encoder->CreateFrame();
	while (isSaveing)
	{
		std::list<char*> mList = TonyCaptureScreen::Get()->getScreenDataList();
		if (!mList.empty())
		{
			char* data = mList.front();
			frame->pts = count;
			encoder->scale((uint8_t*)data, frame);
			auto pkt = encoder->Encode(frame);
			if (pkt)
			{
				writer->Write((char*)pkt->data, pkt->size);
				av_packet_free(&pkt);
			}
			mList.pop_front();
			count++;
		}
	}
	//取出编码缓冲区中的数据，也就是最后几帧
	auto pkts = encoder->End();
	for (auto pkt : pkts)
	{
		writer->Write((char*)pkt->data, pkt->size);
		av_packet_free(&pkt);
	}
	encoder->setContext(nullptr);
	if (frame)
	{
		av_frame_free(&frame);
	}
	qDebug() << "数据保存结束";

}

void GenerateH26XWindow::closeEvent(QCloseEvent* event) {
	event->accept();  // 接受关闭事件（允许关闭）
	if (isClickedRecord) {
		TonyCaptureScreen::Get()->Stop();
		isSaveing = false;
		if (renderThread && renderThread->joinable()) {
			renderThread->join();
		}
		if (writer) {
			writer->Close();
			writer = nullptr;
		}
		if (encoder) {
			encoder->Release();
			delete encoder;
			encoder = nullptr;
		}

	}
	qDebug() << "窗口已关闭";
}

GenerateH26XWindow::~GenerateH26XWindow()
{
}
